package com.wstuo.common.config.onlinelog.aop;

import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.apache.logging.log4j.Level;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.context.ApplicationContext;

import com.wstuo.common.dto.AnnotationPropertyDTO;
import com.wstuo.common.security.utils.AppConfigUtils;
import com.wstuo.common.util.AppliactionBaseListener;
import com.wstuo.common.util.LogUtils;
import com.wstuo.common.util.TimeUtils;
import com.wstuo.multitenancy.TenantIdResolver;

public class UserOptErrorLogAspect {
	private static final Logger LOGGER = Logger.getLogger(UserOptErrorLogAspect.class);
//	@Autowired
//	private ICache cacheService;
	
	@SuppressWarnings("unused")
	public Object around(ProceedingJoinPoint jp) throws Throwable {

		Object obj = null;
		long execTime = 0;
		String methodName = jp.getSignature().getName();

		String resourceName = jp.getTarget().getClass().getName();
		if (resourceName.endsWith("Service")) {
			int s = resourceName.lastIndexOf(".") + 1;
			int e = resourceName.lastIndexOf("Service");
			resourceName = resourceName.substring(s, e);
		}
		Long dtoId = null;
		try {
			dtoId = getDtoId(jp.getArgs());
		} catch (Exception e) {
			LOGGER.error(e.getMessage());
		}

		StringWriter sw = null;
		ApplicationContext ctx = AppliactionBaseListener.ctx;
		try {
			long begin = System.currentTimeMillis();
			obj = jp.proceed();

			long end = System.currentTimeMillis();
			execTime = end - begin;
		} catch (Exception e) {
			String errCause = "";
			if (null != e){
				errCause = LogUtils.getStackTrace(e);
			}
			String tenantId = TenantIdResolver.getInstance().getDefaultTenantId();
			String filePath =  AppConfigUtils.getInstance().getDefaultErrLogPath();
    		if(!"Unknown user".equals(getUsername())){
    			/*System.out.println("UserOptErrorLogAspect.around(deeeee)"+getUsername());
    			Object cacheValue = cacheService.getValue(getUsername());
	    		if(cacheValue!=null){
	    			tenantId = cacheValue.toString();
	    		}else{
	    			System.out.println("UserOptErrorLogAspect.around()"+cacheValue);
	    			LOGGER.error("Key:"+getUsername()+",can not find tenantId!");
	    		}*/
	    		filePath =  AppConfigUtils.getInstance().getErrLogPath(tenantId);
    		}
    		String resId = "0";
    		if(null != dtoId){
    			resId = dtoId.toString();
    		}
    		
    		filePath = filePath+"/userErrLog.txt";
    		String loggerName = "userErrLog"+tenantId;
			String date = TimeUtils.format(new Date(), TimeUtils.DATETIME_PATTERN);
			org.apache.logging.log4j.Logger logger = LogUtils.getOptErrorLog(filePath, loggerName,getUsername(),date,methodName,resourceName,e.getMessage(),errCause,resId);
			logger.log(Level.INFO, "");
			throw e;
		}
		return obj;
	}
	
	public Long getDtoId(Object[] args) throws IllegalAccessException,
	InvocationTargetException, NoSuchMethodException {
		Long dtoId = null;
		
		if (args.length == 1) {
			Object arg = args[0];
		
			// add mars @20110630
			AnnotationPropertyDTO adto = null;
		
			if (arg != null) {
				adto = arg.getClass().getAnnotation(AnnotationPropertyDTO.class);
			}
			if (adto != null) {
				String idName = adto.id();
				dtoId = (Long) PropertyUtils.getSimpleProperty(arg, idName);
			} else if (arg instanceof Long) {
				dtoId = (Long) arg;
			}
		}
		
		return dtoId;
	}
	
	public String getUsername() {
		String username = "Unknown user";

		if (SecurityContextHolder.getContext().getAuthentication() != null) {
			Object principal = SecurityContextHolder.getContext()
					.getAuthentication().getPrincipal();

			if (principal instanceof UserDetails) {
				username = ((UserDetails) principal).getUsername();
			} else {
				username = principal.toString();
			}
		}

		return username;
	}
	
}
